package br.com.viamais.infra.dao;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Session;

import br.com.viamais.infra.model.BaseEntity;
import br.com.viamais.util.HibernateUtil;

/**
 * Abstract class to implements methods of BaseSession. TODO: Logger
 * 
 * @author Eduardo T. Serete. May 25, 2011. 1:18:12 AM
 */
public abstract class BaseDAO<T extends BaseEntity> implements IBaseDAO<T> {

	/**
	 * Default constructor.
	 */
	public BaseDAO() {
		super();
		this.session = HibernateUtil.getSession();
	}

	/**
	 * Generated serial version id.
	 */
	private static final long serialVersionUID = -8200992381537905411L;

	/**
	 * Session
	 */
	private Session session;

	/**
	 * To get current session
	 * 
	 * @return Session
	 * @throws Throwable
	 *             : Hibernate configuration problems.
	 */
	public Session getSession() throws Throwable {
		if (session == null) {
			session = HibernateUtil.getSession();
		}
		return session;
	}

	/**
	 * Begin the transaction.
	 * 
	 * @throws Throwable
	 *             : Connections issues.
	 */
	public void beginTransaction() throws Throwable {
		this.getSession().beginTransaction();
	}

	/**
	 * Do commit.
	 * 
	 * @throws Throwable
	 *             : Connections issues.
	 */
	public void commit() throws Throwable {
		this.getSession().getTransaction().commit();
	}

	/**
	 * Roll back the alterations in database.
	 * 
	 * @throws Throwable
	 *             : Connections issues.
	 */
	public void rollBack() throws Throwable {
		this.getSession().getTransaction().rollback();
	}

	/**
	 * Flush the session to force exit.
	 * 
	 * @throws Throwable
	 *             : Connections issues.
	 */
	public void flush() throws Throwable {
		this.getSession().flush();
	}

	/**
	 * Return the class of type. If not implemented some methods will not work.
	 * 
	 * @return Class<T>:class of type.
	 */
	protected abstract Class<T> getClazz();

	/**
	 * {@inheritDoc}
	 * @return 
	 */
	@Override
	public void saveOrUpdate(T entity) throws Throwable {
		if (entity != null) {
			this.beginTransaction();
			this.getSession().saveOrUpdate(entity);
			this.commit();
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void delete(final T entity) throws Throwable {
		if (entity != null) {
			this.beginTransaction();
			this.getSession().delete(entity);
			this.commit();
		}

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@SuppressWarnings("unchecked")
	public List<T> getAll() throws Throwable {
		List<T> entities;
		this.beginTransaction();
		Criteria criteria = this.getSession().createCriteria(this.getClazz());
		entities = (List<T>) criteria.list();
		this.commit();
		return entities;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@SuppressWarnings("unchecked")
	public T getById(Integer id) throws Throwable {
		T result = null;
		if(id != null) {
			this.beginTransaction();
			result = (T) this.getSession().get(getClazz(), id);
			this.commit();
		}
		return result;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@SuppressWarnings("unchecked")
	public T load(Integer id) throws Throwable {
		T result = null;
		if(id != null) {
			this.beginTransaction();
			result = (T) this.getSession().load(getClazz(), id);
			this.commit();
		}
		return result;
	}

}
